# -*- coding: utf-8 -*-

import itertools
import pathlib

import numpy as np
import numpy.linalg as LA
from PIL import Image

"""Extension of PIL

I am sorry this is not completed version of PIL_ext.
The completed version see ???
"""


class Background:
    '''The background where you paint.
    
    You can paint with pictures instead of pixels.
    '''

    def __init__(self, nrow, ncol, size=(50, 50), mode='RGB', *args, **kwargs):
        '''
        Arguments:
            nrow {int} -- [the number of rows]
            ncol {int} -- [the number of columns]
        
        Keyword Arguments:
            size {tuple|int} -- [the size of pictures] (default: {(50, 50)})
            mode {str} -- [mode of image] (default: {'RGB'})
        '''
        if isinstance(size, int):
            size = (size, size)
        self.image = Image.new(mode, (ncol*size[0], nrow*size[1]))
        self.nrow = nrow
        self.ncol = ncol
        self.size = size
        self.mode = mode

    def paste(self, img, coord=(0, 0), scale=None):
        '''Embed a image into the background
        
        Embed an image `img` into the background at coordinate `coord`, 
        Like ploting a point in an convas.
        
        Arguments:
            img {Image} -- [a small picture]
        
        Keyword Arguments:
            coord {tuple} -- [coordinate] (default: {(0, 0)})
            scale {int} -- scaling the small image
        '''
        x, y = coord
        if scale:
            size = self.size[0] * scale, self.size[1] * scale
            img = img.resize(size)
        else:
            img = img.resize(self.size)
        self.image.paste(img, (x * self.size[0], y * self.size[1]))

    def save(self, *args, **kwargs):
        self.image.save(*args, **kwargs)

    def draw(self, imgs, coords):
        '''Embed several images into the background.

        imgs[k] will be loacated at coords[k]

        Arguments:
            imgs {[Image]} -- list of images
            coords {[tuple]} -- list of coordinates
        '''

        for img, coord in zip(itertools.cycle(imgs), coords):
            self.paste(img, coord)

def patch(imgs, big):
    """
    Patch a big image with small images

    Arguments:
        imgs {List[Image]} -- list of images
        big {Image} -- big image
    
    Returns:
        an image
    """
    bg = Background(big.size[1], big.size[0], size=imgs[0].size)
    a = np.asarray(big, dtype=np.float64)
    means = [np.asarray(img, dtype=np.float64).mean(axis=(0,1)) for img in imgs if img.mode=='RGB']
    for i in range(big.size[1]):
        for j in range(big.size[0]):
            p = a[i, j, :]
            k = np.argmin([LA.norm(p-m) for m in means])
            bg.paste(imgs[k], (j, i))
    return bg.image
